`timescale 1ns/1ns

class Transaction;
    rand bit [31:0] data;
    rand bit [3:0]  kind; 
endclass

interface busifc (input logic clk);
    logic [31:0] data;
    logic [3:0]  kind;

    clocking cb @(posedge clk);
        default input #1step output #2;
        output data, kind;
    endclocking

    modport TB (clocking cb);
    
    modport DUT (input clk, data, kind);
endinterface

module DUT (busifc.DUT ifc);
    // 在始终上升沿处, 输出相关信号
    // 其值由当前时钟上升沿之前时间点驱动
    always @(ifc.clk) begin
        $display("[DUT @ %0t] RECV\tKind: %d, Data: %h @(ifc.clk)", $time, ifc.kind, ifc.data);
    end
endmodule

program automatic TB (busifc.TB ifc);

    Transaction tr;

    // 定义 covergroup, 其可包含若干 coverpoint
    covergroup CovKind;
        // coverpoint 定义为采样变量(或表达式)
        coverpoint tr.kind {
            // 每个 coverpoint 有一组 bins
            // 自定义分箱
            bins zero = {0};        // 仅当 kind 为 0 时命中
            bins low  = {[1:3], 5}; // 当 kind 为 1, 2, 3 或 5 时命中
            bins high = {[8:$]};    // 当 kind 为 8 及以上时命中
            bins misc = default;    // 其他情况命中
        }
    endgroup

    CovKind ck = new;

    initial begin
        tr = new();
        ck = new();

        $display("[TB] Starting TB...");

        repeat (128) begin
            @(ifc.cb);

            if (!tr.randomize()) begin
                $error("Randomization failed!");
            end

            $display("[TB  @ %0t] SEND\tKind: %d, Data: %h", $time, tr.kind, tr.data);

            // 通过 clocking block 将数据驱动到接口上
            ifc.cb.kind <= tr.kind;
            ifc.cb.data <= tr.data;

            // 采样覆盖率
            ck.sample();
        end

        $display("[TB] Test finished.");
  end

endprogram

module coverage_bins;
    logic clk = 0;
    initial begin
        forever #5 clk = ~clk;
    end

    busifc ifc(clk);

    DUT dut(.ifc(ifc.DUT));

    TB  tb(.ifc(ifc.TB));

endmodule
